/*
要解决之前遇到的修改a触发b的effect函数执行的问题，需要设计一种数据结构，存储对象中每个字段对应的effect函数
比如： target = {a:"123",b:-1}
要达到的效果就是
-target
---a
-----a的effect
---b
-----b的effect
这样，触发target.a的修改时，不会执行b的effect, 存储结构为一个树形结构
*/

// 修改存放effect的桶的数据结构
// bucket存储所有的响应式obj对应的depsMap, depsMap通过key找到对应effects
const bucket = new WeakMap()

const data = { text: 'hello world' }

// 副作用注册函数
let activeEffect // 用于标记，因为需要手动执行一次effect(fn)，fn中会触发get操作，收集effect的fn
function effect(fn) {
  activeEffect = fn
  fn()
}

// 依赖收集的函数
function track(target, key) {
  if (!activeEffect) return
  // 从bucket中获取出depsMap，是一个Map类型, key-effects
  let depsMap = bucket.get(target)
  // 不存在depsMap则新建
  if (!depsMap) bucket.set(target, (depsMap = new Map()))
  // key对应的所有依赖
  let deps = depsMap.get(key)
  if (!deps) depsMap.set(key, (deps = new Set()))
  deps.add(activeEffect)
}

// 触发effect
function trigger(target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  const deps = depsMap.get(key)
  deps && deps.forEach((effectFn) => effectFn())
}

const obj = new Proxy(data, {
  // 拦截读取操作
  get(target, key) {
    track(target, key)
    return Reflect.get(target, key)
  },
  // 拦截设置操作
  set(target, key, val) {
    Reflect.set(target, key, val)
    trigger(target, key)
    return true
  },
})

// 注册effect函数
effect(function listenText() {
  console.count('listenText')
  document.body.innerText = obj.text
})
setTimeout(() => {
  obj.anotherText = '我变化了'
}, 2000)
setTimeout(() => {
  obj.text = '我也变化了'
}, 3000)
